
<!DOCTYPE html>
<html
  lang="zh-cn"
  data-figures=""
  
    class="page"
  
  
  >
  <head>
<title>Linux 0号线程swapper简介 | 拾月国度</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<script>
  var _hmt = _hmt || [];
  (function() {
    var hm = document.createElement("script");
    hm.src = "https://hm.baidu.com/hm.js?c24bad48a3da8c3c532f0c580bb4f8c5";
    var s = document.getElementsByTagName("script")[0];
    s.parentNode.insertBefore(hm, s);
  })();
</script>





<meta property="og:locale" content="zh-cn" />

<meta property="og:type" content="article">
<meta name="description" content="1. 总览 这里以ARM64为例。
在内核的起始阶段，还没有进程和线程的概念，在开启MMU之后，__primary_switched的第一步就是将init_task的地址写到sp_el0，这个时候就可以用get_current()或者curent获取到0号线程的task_struct了。在0号线程的上下文，完成调度器的 …" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:creator" content="">
<meta name="twitter:title" content="Linux 0号线程swapper简介" />
<meta name="twitter:image" content="https://kingdix10.gitee.io/covers/cover7.jpg"/>
<meta property="og:url" content="https://kingdix10.gitee.io/post/kernel/linux-6.1/sched/task_0/" />
<meta property="og:title" content="Linux 0号线程swapper简介" />
<meta property="og:description" content="1. 总览 这里以ARM64为例。
在内核的起始阶段，还没有进程和线程的概念，在开启MMU之后，__primary_switched的第一步就是将init_task的地址写到sp_el0，这个时候就可以用get_current()或者curent获取到0号线程的task_struct了。在0号线程的上下文，完成调度器的 …" />
<meta property="og:image" content="https://kingdix10.gitee.io/covers/cover7.jpg" />

<link rel="apple-touch-icon" sizes="180x180" href="https://kingdix10.gitee.io/icons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="https://kingdix10.gitee.io/icons/icon_yellow_transparent.png">
<link rel="manifest" href="https://kingdix10.gitee.io/icons/site.webmanifest">

<link rel="canonical" href="https://kingdix10.gitee.io/post/kernel/linux-6.1/sched/task_0/">



<link rel="preload" href="https://kingdix10.gitee.io/css/styles.42e2c5f6d8cf9c52872666f8d8b2678ad0c426978b9d78aff3c33b7a1e7f6f97f54bcdaf0518a25fb0fe26367d04f8b07c683b3b38b331cb098daadee06b1f3e.css" integrity = "sha512-QuLF9tjPnFKHJmb42LJnitDEJpeLnXiv88M7eh5/b5f1S82vBRiiX7D&#43;JjZ9BPiwfGg7OzizMcsJjare4GsfPg==" as="style" crossorigin="anonymous">



<link rel="preload" href="https://kingdix10.gitee.io/zh-cn/js/bundle.352f6b8ac853443fc909370d968a769ffa303b36042cc66849f2d48d9e5dd951ee86c06130908f5d77ea0e55ec8fed0e5dc26f0f14bbd4ad6dcf35999232e5bc.js" as="script" integrity=
"sha512-NS9rishTRD/JCTcNlop2n/owOzYELMZoSfLUjZ5d2VHuhsBhMJCPXXfqDlXsj&#43;0OXcJvDxS71K1tzzWZkjLlvA==" crossorigin="anonymous">


<link rel="stylesheet" type="text/css" href="https://kingdix10.gitee.io/css/styles.42e2c5f6d8cf9c52872666f8d8b2678ad0c426978b9d78aff3c33b7a1e7f6f97f54bcdaf0518a25fb0fe26367d04f8b07c683b3b38b331cb098daadee06b1f3e.css" integrity="sha512-QuLF9tjPnFKHJmb42LJnitDEJpeLnXiv88M7eh5/b5f1S82vBRiiX7D&#43;JjZ9BPiwfGg7OzizMcsJjare4GsfPg==" crossorigin="anonymous">

  </head>
  <body
    data-code="9"
    data-lines="true"
    id="documentTop"
    data-lang="zh-cn"
  >

<header class="nav_header" >
  <nav class="nav"><a href='https://kingdix10.gitee.io/' class="nav_brand nav_item" title="拾月国度">
  <img src="https://kingdix10.gitee.io/logos/icon_yellow_transparent_72x72.png" class="logo" alt="拾月国度">
  <div class="nav_close">
    <div><svg class="icon">
  <title>open-menu</title>
  <use xlink:href="#open-menu"></use>
</svg>
<svg class="icon">
  <title>closeme</title>
  <use xlink:href="#closeme"></use>
</svg>
</div>
  </div>
</a>

    <div class='nav_body nav_body_left'>
      
      
      
        

  <div class="nav_parent">
    <a href="https://kingdix10.gitee.io/home" class="nav_item" title="主页">主页 </a>
  </div>
  <div class="nav_parent">
    <a href="https://kingdix10.gitee.io/" class="nav_item" title="归档">归档 </a>
  </div>
  <div class="nav_parent">
    <a href="https://kingdix10.gitee.io/" class="nav_item" title="链接">链接 <img src='https://kingdix10.gitee.io/icons/caret-icon.svg' alt="icon" class="nav_icon"></a>
    <div class="nav_sub">
      <span class="nav_child"></span>
        <a href="https://gitee.com/kingdix10" class="nav_child nav_item" title="Gitee">Gitee</a>
        <a href="https://github.com/kingdix10" class="nav_child nav_item" title="GitHub">GitHub</a>
        <a href="https://www.zhihu.com/people/kingdix10" class="nav_child nav_item" title="知乎">知乎</a>
        <a href="https://www.cnblogs.com/kingdix10" class="nav_child nav_item" title="博客园">博客园</a>
        <a href="https://blog.csdn.net/u014001096" class="nav_child nav_item" title="CSDN">CSDN</a>
    </div>
  </div>
  <div class="nav_parent">
    <a href="https://kingdix10.gitee.io/about/" class="nav_item" title="关于">关于 </a>
  </div>
      
      <div class="nav_parent">
        <a href="#" class="nav_item">🌐</a>
        <div class="nav_sub">
          <span class="nav_child"></span>
          
          <a href="https://kingdix10.gitee.io/" class="nav_child nav_item">中文</a>
          
          <a href="https://kingdix10.gitee.io/en/" class="nav_child nav_item">English</a>
          
        </div>
      </div>
<div class='follow'>
  <a href="https://gitee.com/kingdix10">
    <svg class="icon">
  <title>gitee</title>
  <use xlink:href="#gitee"></use>
</svg>

  </a>
  <a href="https://github.com/kingdix10">
    <svg class="icon">
  <title>github</title>
  <use xlink:href="#github"></use>
</svg>

  </a>
    
  <a href="https://kingdix10.gitee.io/index.xml">
    <svg class="icon">
  <title>rss</title>
  <use xlink:href="#rss"></use>
</svg>

  </a>
<div class="color_mode">
  <input type="checkbox" class="color_choice" id="mode">
</div>

</div>

    </div>
  </nav>
</header>

    <main>
<div class="grid-inverse wrap content">
  <article class="post_content">
    <h1 class="post_title">Linux 0号线程swapper简介</h1>
  <div class="post_meta">
    <span><svg class="icon">
  <title>calendar</title>
  <use xlink:href="#calendar"></use>
</svg>
</span>
    <span class="post_date">
      2022/02/05</span>
    <span class="post_time"> | 6 分钟阅读</span><span>&nbsp;|<a href='https://kingdix10.gitee.io/tags/linux%E5%86%85%E6%A0%B8/' title="linux内核" class="post_tag button button_translucent">linux内核
        </a><a href='https://kingdix10.gitee.io/tags/%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86/' title="进程管理" class="post_tag button button_translucent">进程管理
        </a><a href='https://kingdix10.gitee.io/tags/linux-6.1/' title="linux-6.1" class="post_tag button button_translucent">linux-6.1
        </a>
    </span>
    <span class="page_only">&nbsp;|
  <div class="post_share">
    分享到:

    <a href="https://kingdix10.gitee.io/post/kernel/linux-6.1/sched/task_0/" title="Copy Link" class="link link_yank">
      <svg class="icon">
  <title>copy</title>
  <use xlink:href="#copy"></use>
</svg>

    </a>
  </div>
  
</span>
  </div>



      <div class="post_toc">
        <h2>文章目录</h2>
        <nav id="TableOfContents">
  <ul>
    <li><a href="#1-总览">1. 总览</a></li>
    <li><a href="#2-汇编阶段的初始化">2. 汇编阶段的初始化</a></li>
    <li><a href="#3-init_task结构体">3. init_task结构体</a></li>
    <li><a href="#4-bootcpu-0号线程的工作">4. bootcpu 0号线程的工作</a>
      <ul>
        <li><a href="#41-start_kernel">4.1. start_kernel</a></li>
        <li><a href="#42-其他cpu的0号线程创建">4.2. 其他cpu的0号线程创建</a></li>
        <li><a href="#43-创建1号和2号线程">4.3. 创建1号和2号线程</a></li>
        <li><a href="#44-schedule_preempt_disabled">4.4. schedule_preempt_disabled</a></li>
        <li><a href="#45-cpu_startup_entry">4.5. cpu_startup_entry</a></li>
        <li><a href="#46-do_idle">4.6. do_idle</a></li>
      </ul>
    </li>
  </ul>
</nav>
      </div>
    
    <div class="post_body"><h1 id="1-总览">1. 总览</h1>
<p><figure>
  <picture>

    
      
        
        
        
        
        
        
    <img
      loading="lazy"
      decoding="async"
      alt=""
      
        class="image_figure image_internal image_unprocessed"
        src="tasks.png"
      
      
    />

    </picture>
</figure>
</p>
<p>这里以ARM64为例。</p>
<p>在内核的起始阶段，还没有进程和线程的概念，在开启MMU之后，<code>__primary_switched</code>的第一步就是将init_task的地址写到sp_el0，这个时候就可以用get_current()或者curent获取到0号线程的task_struct了。在0号线程的上下文，完成调度器的相关初始化之后，创建1号和2号线程，然后开启调度器，init_task自此进入idle状态。</p>
<p>这里看几个概念：</p>
<ul>
<li>0号线程：对应init_task结构体，名字为swapper，在多处理器中，名称为<code>swapper/&lt;id&gt;</code>，负责内核的一些基础的初始化工作。</li>
<li>1号线程：由0号线程创建，最初的函数为kernel_init，运行在内核态，kernel_init完成一些初始化工作后，通过kernel_execve进入用户态。具体的名字由用户态程序决定。</li>
<li>2号线程：由0号线程创建，回调函数为<code>kthreadd</code>，名字也是<code>kthreadd</code>，所有内核线程的创建都通过2号线程完成。也就是说，所有内核线程的父线程，都是kthreadd。</li>
</ul>
<p>在kernel_init中，smp_init会为每个处理器核心创建一个的swapper线程，其task_struct结构体，并将其绑定到对应的处理器上。
在kernel_init调用的一些初始化函数中，有些会通过kthread或kworker的接口来创建内核线程，这些都内核线程的创建都由kthreadd接管。
在kernel_init最后，通过kernel_execve进入用户态，用户态的init程序，如busybox或systemd等，再通过fork或者clone等系统调用创建新的进程或者线程。</p>
<p>关于0号线程，在init_task中，设置的名字为swapper，在sched_init时，才会通过init_idle将其设置为<code>swapper/&lt;id&gt;</code>，而这个id时bootcpu的id，大多数情况下，bootcpu的id是0，图中展示的就是这种情况。</p>
<h1 id="2-汇编阶段的初始化">2. 汇编阶段的初始化</h1>
<p>使能MMU后，<code>__primary_switched</code>的第一步就是初始化init_task。</p>
<div class="highlight line-numbers"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">/// arch/arm64/kernel/head.S
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"></span><span class="nf">SYM_FUNC_START_LOCAL</span><span class="p">(</span><span class="n">__primary_switched</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="n">adr_l</span>	<span class="n">x4</span><span class="p">,</span> <span class="n">init_task</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="n">init_cpu_task</span> <span class="n">x4</span><span class="p">,</span> <span class="n">x5</span><span class="p">,</span> <span class="n">x6</span>
</span></span></code></pre></div><p>在ARM64中，内核使用sp_el0来记录当前的task_struct。init_cpu_task负责将init_task的地址写入到sp_el0中，设置sp和fp，这个sp是sp_el1或者sp_el2，由内核运行的异常等级决定。</p>
<div class="highlight line-numbers"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">/// arch/arm64/kernel/head.S
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c1"></span>    <span class="cm">/*
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="cm">     * Initialize CPU registers with task-specific and cpu-specific context.
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="cm">     *
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="cm">     * Create a final frame record at task_pt_regs(current)-&gt;stackframe, so
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="cm">     * that the unwinder can identify the final frame record of any task by
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="cm">     * its location in the task stack. We reserve the entire pt_regs space
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="cm">     * for consistency with user tasks and kthreads.
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="cm">     */</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="p">.</span><span class="n">macro</span>  <span class="n">init_cpu_task</span> <span class="n">tsk</span><span class="p">,</span> <span class="n">tmp1</span><span class="p">,</span> <span class="n">tmp2</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="n">msr</span> <span class="n">sp_el0</span><span class="p">,</span> <span class="err">\</span><span class="n">tsk</span>                    <span class="c1">/// 将init_task的地址写入sp_el0，内核运行于EL2或EL1，内核中会使用sp_el0来作为current
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">    <span class="n">ldr</span> <span class="err">\</span><span class="n">tmp1</span><span class="p">,</span> <span class="p">[</span><span class="err">\</span><span class="n">tsk</span><span class="p">,</span> <span class="err">#</span><span class="n">TSK_STACK</span><span class="p">]</span>       <span class="c1">/// 获取init_task的栈地址，offsetof(struct task_struct, stack)
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="c1"></span>    <span class="n">add</span> <span class="n">sp</span><span class="p">,</span> <span class="err">\</span><span class="n">tmp1</span><span class="p">,</span> <span class="err">#</span><span class="n">THREAD_SIZE</span>         <span class="c1">/// 栈是由高地址向下生长的，所以SP_ELx要加上THREAD_SIZE，init_task的栈是静态分配的，它指向init_stack这是一个数组。
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="c1"></span>    <span class="n">sub</span> <span class="n">sp</span><span class="p">,</span> <span class="n">sp</span><span class="p">,</span> <span class="err">#</span><span class="n">PT_REGS_SIZE</span>           <span class="c1">/// 为struct pt_regs留出空间
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="n">stp</span> <span class="n">xzr</span><span class="p">,</span> <span class="n">xzr</span><span class="p">,</span> <span class="p">[</span><span class="n">sp</span><span class="p">,</span> <span class="err">#</span><span class="n">S_STACKFRAME</span><span class="p">]</span>   <span class="c1">/// 将struct pt_regs的u64 stackframe[2]清零
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="c1"></span>    <span class="n">add</span> <span class="n">x29</span><span class="p">,</span> <span class="n">sp</span><span class="p">,</span> <span class="err">#</span><span class="n">S_STACKFRAME</span>          <span class="c1">/// x29(FP)指向栈中pt_regs的stackframe
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">    <span class="n">scs_load</span> <span class="err">\</span><span class="n">tsk</span>                           <span class="c1">/// 此处为空操作，详细信息可以参考arch/Kconfig中的SHADOW_CALL_STACK
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">    <span class="n">adr_l</span>   <span class="err">\</span><span class="n">tmp1</span><span class="p">,</span> <span class="n">__per_cpu_offset</span>         <span class="c1">/// 读取__per_cpu_offset[NR_CPUS]数组基地址
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="c1"></span>    <span class="n">ldr</span> <span class="n">w</span><span class="err">\</span><span class="n">tmp2</span><span class="p">,</span> <span class="p">[</span><span class="err">\</span><span class="n">tsk</span><span class="p">,</span> <span class="err">#</span><span class="n">TSK_TI_CPU</span><span class="p">]</span>     <span class="c1">/// offsetof(struct task_struct, thread_info.cpu)
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="c1"></span>    <span class="n">ldr</span> <span class="err">\</span><span class="n">tmp1</span><span class="p">,</span> <span class="p">[</span><span class="err">\</span><span class="n">tmp1</span><span class="p">,</span> <span class="err">\</span><span class="n">tmp2</span><span class="p">,</span> <span class="n">lsl</span> <span class="err">#</span><span class="mi">3</span><span class="p">]</span>   <span class="c1">/// tmp1 = __per_cpu_offset[init_task.cpu &lt;&lt; 3]，通常来说，bootcpu为0
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="c1"></span>    <span class="n">set_this_cpu_offset</span> <span class="err">\</span><span class="n">tmp1</span>               <span class="c1">/// 将当前cpu的per_cpu变量的offset值写入TPIDR_ELx
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="c1"></span>    <span class="p">.</span><span class="n">endm</span>
</span></span></code></pre></div><h1 id="3-init_task结构体">3. init_task结构体</h1>
<p>内核规定，所有的线程必须由已存在的线程创建出来，也就是所有的task_struct都是在已有的task_struct基础上复制出来的。</p>
<p>内核的初始阶段，内存分配器还没有初始化，无法实现task_struct的动态创建，init_task结构体是在代码中静态声明的。下面展示的是静态声明时，init_task的和其他结构体的关系。</p>
<p>从这里可以看出来，init_mm指定代码段和数据段指向的就是vmlinux的代码段和数据段。</p>
<p><figure>
  <picture>

    
      
        
        
        
        
        
        
    <img
      loading="lazy"
      decoding="async"
      alt="init_task"
      
        class="image_figure image_internal image_unprocessed"
        src="init_task_static.png"
      
      
    />

    </picture>
</figure>
</p>
<h1 id="4-bootcpu-0号线程的工作">4. bootcpu 0号线程的工作</h1>
<h2 id="41-start_kernel">4.1. start_kernel</h2>
<p>汇编结束后，就会进入著名的start_kernel。
这里主要实现调度器和定时器的初始化，以及一些相关变量和kmem_cache的初始化。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">/// init/main.c
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c1"></span>    <span class="c1">/// ... ...
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="c1"></span>    <span class="nf">local_irq_disable</span><span class="p">();</span>        <span class="c1">/// 禁用当前cpu（bootcpu）的中断
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"></span>    <span class="n">early_boot_irqs_disabled</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="c1">/// ... ...
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="cm">/*
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="cm">     * Set up the scheduler prior starting any interrupts (such as the
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="cm">     * timer interrupt). Full topology setup happens at smp_init()
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="cm">     * time - but meanwhile we still have a functioning scheduler.
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="cm">     */</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="nf">sched_init</span><span class="p">();</span>               <span class="c1">/// 调度器初始化
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="c1"></span>    <span class="c1">/// ... ...
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="c1"></span>    <span class="nf">time_init</span><span class="p">();</span>                <span class="c1">/// 定时器初始化，注册clockevent等
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="c1"></span>    <span class="c1">/// ... ...
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="c1"></span>    <span class="n">early_boot_irqs_disabled</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">    <span class="nf">local_irq_enable</span><span class="p">();</span>         <span class="c1">/// 使能当前cpu（bootcpu）的中断
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="c1"></span>    <span class="c1">/// ... ...
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="c1"></span>    <span class="nf">sched_clock_init</span><span class="p">();</span>         <span class="c1">/// 与CONFIG_HAVE_UNSTABLE_SCHED_CLOCK和CONFIG_GENERIC_SCHED_CLOCK相关
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="c1"></span>    <span class="nf">calibrate_delay</span><span class="p">();</span>          <span class="c1">/// 计算lpj
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="c1"></span>    <span class="nf">pid_idr_init</span><span class="p">();</span>             <span class="c1">/// 初始化pid_max和init_pid_ns等
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="c1"></span>    <span class="c1">/// ... ...
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="c1"></span>    <span class="nf">thread_stack_cache_init</span><span class="p">();</span>  <span class="c1">/// 创建thread_stack_cache kmem_cache
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="c1"></span>    <span class="nf">cred_init</span><span class="p">();</span>                <span class="c1">/// 创建cred_jar kmem_cache
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="c1"></span>    <span class="nf">fork_init</span><span class="p">();</span>                <span class="c1">/// task_struct_cachep、rlimit和一些其他初始化
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="c1"></span>    <span class="nf">proc_caches_init</span><span class="p">();</span>         <span class="c1">/// 一些kmem_cache的初始化
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="c1"></span>    <span class="c1">/// ... ...
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="c1"></span>    <span class="cm">/* Do the rest non-__init&#39;ed, we&#39;re now alive */</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">    <span class="nf">arch_call_rest_init</span><span class="p">();</span>      <span class="c1">/// 调用rest_init
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">    <span class="nf">prevent_tail_call_optimization</span><span class="p">();</span>   <span class="c1">/// 实际为mb()，下边是内核给出的注释
</span></span></span><span class="line"><span class="ln">32</span><span class="cl"><span class="c1"></span><span class="cm">/*
</span></span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="cm"> * This is needed in functions which generate the stack canary, see
</span></span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="cm"> * arch/x86/kernel/smpboot.c::start_secondary() for an example.
</span></span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="cm"> */</span>
</span></span></code></pre></div><h2 id="42-其他cpu的0号线程创建">4.2. 其他cpu的0号线程创建</h2>
<p>在bootcpu使用的静态声明的init_task结构体中，comm为swapper，在shced_init时，调用init_idle将其设置为<code>swapper/&lt;id&gt;</code>。
在1号线程开始运行后，smp_init调用idle_threads_init创建非bootcpu的0号线程，并将其设置为<code>swapper/&lt;id&gt;</code>。
percpu变量idle_threads记录每个cpu的0号线程对应的task_struct。</p>
<p><figure>
  <picture>

    
      
        
        
        
        
        
        
    <img
      loading="lazy"
      decoding="async"
      alt=""
      
        class="image_figure image_internal image_unprocessed"
        src="smp_init.png"
      
      
    />

    </picture>
</figure>
</p>
<h2 id="43-创建1号和2号线程">4.3. 创建1号和2号线程</h2>
<p>0号线程的最后，会创建1号和2号线程，开启完整的调度。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">/// init/main.c
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c1"></span><span class="k">static</span> <span class="n">__initdata</span> <span class="nf">DECLARE_COMPLETION</span><span class="p">(</span><span class="n">kthreadd_done</span><span class="p">);</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="n">noinline</span> <span class="kt">void</span> <span class="n">__ref</span> <span class="nf">rest_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="k">struct</span> <span class="n">task_struct</span> <span class="o">*</span><span class="n">tsk</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="kt">int</span> <span class="n">pid</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="nf">rcu_scheduler_starting</span><span class="p">();</span>       <span class="c1">/// 启动RCU（Read-Copy-Update）机制
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="c1"></span>    <span class="cm">/*
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="cm">     * We need to spawn init first so that it obtains pid 1, however
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="cm">     * the init task will end up wanting to create kthreads, which, if
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="cm">     * we schedule it before we create kthreadd, will OOPS.
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="cm">     */</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">    <span class="n">pid</span> <span class="o">=</span> <span class="nf">user_mode_thread</span><span class="p">(</span><span class="n">kernel_init</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">CLONE_FS</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="cm">/*
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="cm">     * Pin init on the boot CPU. Task migration is not properly working
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="cm">     * until sched_init_smp() has been run. It will set the allowed
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="cm">     * CPUs for init to the non isolated CPUs.
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="cm">     */</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">    <span class="nf">rcu_read_lock</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">    <span class="n">tsk</span> <span class="o">=</span> <span class="nf">find_task_by_pid_ns</span><span class="p">(</span><span class="n">pid</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">init_pid_ns</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">    <span class="n">tsk</span><span class="o">-&gt;</span><span class="n">flags</span> <span class="o">|=</span> <span class="n">PF_NO_SETAFFINITY</span><span class="p">;</span>    <span class="c1">/// 不允许用户程序操作cpus_mask
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="c1"></span>    <span class="nf">set_cpus_allowed_ptr</span><span class="p">(</span><span class="n">tsk</span><span class="p">,</span> <span class="nf">cpumask_of</span><span class="p">(</span><span class="nf">smp_processor_id</span><span class="p">()));</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">    <span class="nf">rcu_read_unlock</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">
</span></span><span class="line"><span class="ln">27</span><span class="cl">    <span class="nf">numa_default_policy</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">    <span class="n">pid</span> <span class="o">=</span> <span class="nf">kernel_thread</span><span class="p">(</span><span class="n">kthreadd</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">CLONE_FS</span> <span class="o">|</span> <span class="n">CLONE_FILES</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">    <span class="nf">rcu_read_lock</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">    <span class="n">kthreadd_task</span> <span class="o">=</span> <span class="nf">find_task_by_pid_ns</span><span class="p">(</span><span class="n">pid</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">init_pid_ns</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">    <span class="nf">rcu_read_unlock</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">
</span></span><span class="line"><span class="ln">33</span><span class="cl">    <span class="cm">/*
</span></span></span><span class="line"><span class="ln">34</span><span class="cl"><span class="cm">     * Enable might_sleep() and smp_processor_id() checks.
</span></span></span><span class="line"><span class="ln">35</span><span class="cl"><span class="cm">     * They cannot be enabled earlier because with CONFIG_PREEMPTION=y
</span></span></span><span class="line"><span class="ln">36</span><span class="cl"><span class="cm">     * kernel_thread() would trigger might_sleep() splats. With
</span></span></span><span class="line"><span class="ln">37</span><span class="cl"><span class="cm">     * CONFIG_PREEMPT_VOLUNTARY=y the init task might have scheduled
</span></span></span><span class="line"><span class="ln">38</span><span class="cl"><span class="cm">     * already, but it&#39;s stuck on the kthreadd_done completion.
</span></span></span><span class="line"><span class="ln">39</span><span class="cl"><span class="cm">     */</span>
</span></span><span class="line"><span class="ln">40</span><span class="cl">    <span class="n">system_state</span> <span class="o">=</span> <span class="n">SYSTEM_SCHEDULING</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">41</span><span class="cl">
</span></span><span class="line"><span class="ln">42</span><span class="cl">    <span class="c1">/// kernel_init可能会创建内核线程，kernel_init最开始会等待kthreadd线程创建完成
</span></span></span><span class="line"><span class="ln">43</span><span class="cl"><span class="c1"></span>    <span class="nf">complete</span><span class="p">(</span><span class="o">&amp;</span><span class="n">kthreadd_done</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">44</span><span class="cl">
</span></span><span class="line"><span class="ln">45</span><span class="cl">    <span class="cm">/*
</span></span></span><span class="line"><span class="ln">46</span><span class="cl"><span class="cm">     * The boot idle thread must execute schedule()
</span></span></span><span class="line"><span class="ln">47</span><span class="cl"><span class="cm">     * at least once to get things moving:
</span></span></span><span class="line"><span class="ln">48</span><span class="cl"><span class="cm">     */</span>
</span></span><span class="line"><span class="ln">49</span><span class="cl">    <span class="c1">/// bootcpu的idle程序需要调用schedule来使能调度，这样1号和2号线程才可以运行。
</span></span></span><span class="line"><span class="ln">50</span><span class="cl"><span class="c1"></span>    <span class="nf">schedule_preempt_disabled</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">51</span><span class="cl">    <span class="cm">/* Call into cpu_idle with preempt disabled */</span>
</span></span><span class="line"><span class="ln">52</span><span class="cl">    <span class="nf">cpu_startup_entry</span><span class="p">(</span><span class="n">CPUHP_ONLINE</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">53</span><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="44-schedule_preempt_disabled">4.4. schedule_preempt_disabled</h2>
<p>init_task的thread_info的preempt_count初始化为INIT_PREEMPT_COUNT。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">/// include/linux/preempt.h
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"></span><span class="cm">/*
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="cm"> * Disable preemption until the scheduler is running -- use an unconditional
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="cm"> * value so that it also works on !PREEMPT_COUNT kernels.
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="cm"> *
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="cm"> * Reset by start_kernel()-&gt;sched_init()-&gt;init_idle()-&gt;init_idle_preempt_count().
</span></span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="cp">#define INIT_PREEMPT_COUNT	PREEMPT_OFFSET
</span></span></span></code></pre></div><p>这里在关闭抢占的情况下打开调度。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">/// kernel/sched/core.c
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c1"></span><span class="cm">/*
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="cm"> * schedule_preempt_disabled - called with preemption disabled
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="cm"> *
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="cm"> * Returns with preemption disabled. Note: preempt_count must be 1
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="kt">void</span> <span class="n">__sched</span> <span class="nf">schedule_preempt_disabled</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="nf">sched_preempt_enable_no_resched</span><span class="p">();</span>  <span class="c1">/// 打开抢占，但是不进行调度
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="c1"></span>    <span class="nf">schedule</span><span class="p">();</span>                         <span class="c1">/// 主动调度，使1号和2号线程可以运行
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="c1"></span>    <span class="nf">preempt_disable</span><span class="p">();</span>                  <span class="c1">/// 重新关闭抢占，swapper是最后被选择的进程，不会有其他进程抢占
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><h2 id="45-cpu_startup_entry">4.5. cpu_startup_entry</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">/// kernel/sched/core.c
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"></span><span class="kt">void</span> <span class="nf">cpu_startup_entry</span><span class="p">(</span><span class="k">enum</span> <span class="n">cpuhp_state</span> <span class="n">state</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="nf">arch_cpu_idle_prepare</span><span class="p">();</span>    <span class="c1">/// 默认为空
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="c1"></span>    <span class="nf">cpuhp_online_idle</span><span class="p">(</span><span class="n">state</span><span class="p">);</span>   <span class="c1">/// cpu hotplug相关
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="c1"></span>    <span class="k">while</span> <span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">        <span class="nf">do_idle</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="46-do_idle">4.6. do_idle</h2>
<p>do_idle的主要工作就是检查swapper是否需要重新调度，如果不需要，则一直循环，如果处理器支持，进入低功耗状态，等待处理器被唤醒。否则通过schedule_idle调度其他进程运行。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">/// kernel/sched/idle.c
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c1"></span><span class="cm">/*
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="cm"> * Generic idle loop implementation
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="cm"> *
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="cm"> * Called with polling cleared.
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="cm"> */</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="k">static</span> <span class="kt">void</span> <span class="nf">do_idle</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="kt">int</span> <span class="n">cpu</span> <span class="o">=</span> <span class="nf">smp_processor_id</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="cm">/*
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="cm">     * Check if we need to update blocked load
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="cm">     */</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">    <span class="nf">nohz_run_idle_balance</span><span class="p">(</span><span class="n">cpu</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">
</span></span><span class="line"><span class="ln">16</span><span class="cl">    <span class="cm">/*
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="cm">     * If the arch has a polling bit, we maintain an invariant:
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="cm">     *
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="cm">     * Our polling bit is clear if we&#39;re not scheduled (i.e. if rq-&gt;curr !=
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="cm">     * rq-&gt;idle). This means that, if rq-&gt;idle has the polling bit set,
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="cm">     * then setting need_resched is guaranteed to cause the CPU to
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="cm">     * reschedule.
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="cm">     */</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">
</span></span><span class="line"><span class="ln">25</span><span class="cl">    <span class="nf">__current_set_polling</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">    <span class="nf">tick_nohz_idle_enter</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">
</span></span><span class="line"><span class="ln">28</span><span class="cl">    <span class="c1">/// 如果不需要重新调度，一直循环，如果处理器支持，进入低功耗状态，等待处理器被唤醒
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="c1"></span>    <span class="k">while</span> <span class="p">(</span><span class="o">!</span><span class="nf">need_resched</span><span class="p">())</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">30</span><span class="cl">        <span class="nf">rmb</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">
</span></span><span class="line"><span class="ln">32</span><span class="cl">        <span class="nf">local_irq_disable</span><span class="p">();</span>        <span class="c1">/// 在cpu_idle_poll或cpuidle_idle_call会重新使能中断
</span></span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="ln">34</span><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="nf">cpu_is_offline</span><span class="p">(</span><span class="n">cpu</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">35</span><span class="cl">            <span class="nf">tick_nohz_idle_stop_tick</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">36</span><span class="cl">            <span class="nf">cpuhp_report_idle_dead</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">37</span><span class="cl">            <span class="nf">arch_cpu_idle_dead</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">38</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">39</span><span class="cl">
</span></span><span class="line"><span class="ln">40</span><span class="cl">        <span class="nf">arch_cpu_idle_enter</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">41</span><span class="cl">        <span class="nf">rcu_nocb_flush_deferred_wakeup</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">42</span><span class="cl">
</span></span><span class="line"><span class="ln">43</span><span class="cl">        <span class="cm">/*
</span></span></span><span class="line"><span class="ln">44</span><span class="cl"><span class="cm">         * In poll mode we reenable interrupts and spin. Also if we
</span></span></span><span class="line"><span class="ln">45</span><span class="cl"><span class="cm">         * detected in the wakeup from idle path that the tick
</span></span></span><span class="line"><span class="ln">46</span><span class="cl"><span class="cm">         * broadcast device expired for us, we don&#39;t want to go deep
</span></span></span><span class="line"><span class="ln">47</span><span class="cl"><span class="cm">         * idle as we know that the IPI is going to arrive right away.
</span></span></span><span class="line"><span class="ln">48</span><span class="cl"><span class="cm">         */</span>
</span></span><span class="line"><span class="ln">49</span><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">cpu_idle_force_poll</span> <span class="o">||</span> <span class="nf">tick_check_broadcast_expired</span><span class="p">())</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">50</span><span class="cl">            <span class="nf">tick_nohz_idle_restart_tick</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">51</span><span class="cl">            <span class="nf">cpu_idle_poll</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">52</span><span class="cl">        <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">53</span><span class="cl">            <span class="nf">cpuidle_idle_call</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">54</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln">55</span><span class="cl">        <span class="nf">arch_cpu_idle_exit</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">56</span><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="ln">57</span><span class="cl">
</span></span><span class="line"><span class="ln">58</span><span class="cl">    <span class="c1">/// 如果需要重新调度，则运行其他进程
</span></span></span><span class="line"><span class="ln">59</span><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="ln">60</span><span class="cl">    <span class="cm">/*
</span></span></span><span class="line"><span class="ln">61</span><span class="cl"><span class="cm">     * Since we fell out of the loop above, we know TIF_NEED_RESCHED must
</span></span></span><span class="line"><span class="ln">62</span><span class="cl"><span class="cm">     * be set, propagate it into PREEMPT_NEED_RESCHED.
</span></span></span><span class="line"><span class="ln">63</span><span class="cl"><span class="cm">     *
</span></span></span><span class="line"><span class="ln">64</span><span class="cl"><span class="cm">     * This is required because for polling idle loops we will not have had
</span></span></span><span class="line"><span class="ln">65</span><span class="cl"><span class="cm">     * an IPI to fold the state for us.
</span></span></span><span class="line"><span class="ln">66</span><span class="cl"><span class="cm">     */</span>
</span></span><span class="line"><span class="ln">67</span><span class="cl">    <span class="nf">preempt_set_need_resched</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">68</span><span class="cl">    <span class="nf">tick_nohz_idle_exit</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">69</span><span class="cl">    <span class="nf">__current_clr_polling</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">70</span><span class="cl">
</span></span><span class="line"><span class="ln">71</span><span class="cl">    <span class="cm">/*
</span></span></span><span class="line"><span class="ln">72</span><span class="cl"><span class="cm">     * We promise to call sched_ttwu_pending() and reschedule if
</span></span></span><span class="line"><span class="ln">73</span><span class="cl"><span class="cm">     * need_resched() is set while polling is set. That means that clearing
</span></span></span><span class="line"><span class="ln">74</span><span class="cl"><span class="cm">     * polling needs to be visible before doing these things.
</span></span></span><span class="line"><span class="ln">75</span><span class="cl"><span class="cm">     */</span>
</span></span><span class="line"><span class="ln">76</span><span class="cl">    <span class="nf">smp_mb__after_atomic</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">77</span><span class="cl">
</span></span><span class="line"><span class="ln">78</span><span class="cl">    <span class="cm">/*
</span></span></span><span class="line"><span class="ln">79</span><span class="cl"><span class="cm">     * RCU relies on this call to be done outside of an RCU read-side
</span></span></span><span class="line"><span class="ln">80</span><span class="cl"><span class="cm">     * critical section.
</span></span></span><span class="line"><span class="ln">81</span><span class="cl"><span class="cm">     */</span>
</span></span><span class="line"><span class="ln">82</span><span class="cl">    <span class="nf">flush_smp_call_function_queue</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">83</span><span class="cl">    <span class="nf">schedule_idle</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">84</span><span class="cl">
</span></span><span class="line"><span class="ln">85</span><span class="cl">    <span class="c1">/// 重新进入idll进程时，检查是否有kernel livepatch
</span></span></span><span class="line"><span class="ln">86</span><span class="cl"><span class="c1"></span>    <span class="k">if</span> <span class="p">(</span><span class="nf">unlikely</span><span class="p">(</span><span class="nf">klp_patch_pending</span><span class="p">(</span><span class="n">current</span><span class="p">)))</span>
</span></span><span class="line"><span class="ln">87</span><span class="cl">        <span class="nf">klp_update_patch_state</span><span class="p">(</span><span class="n">current</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">88</span><span class="cl"><span class="p">}</span>
</span></span></code></pre></div>
    </div><div class="post_comments">
  
  
  
</div>



  </article>
<aside class="sidebar">
  <section class="sidebar_inner">
    <br>
    
  
  <div class="search">
    <input type="search" class="search_field form_field" placeholder='搜索内容...' id="find" autocomplete="off" data-scope='post'>
    <label for="find" class="search_label"><svg class="icon">
  <title>search</title>
  <use xlink:href="#search"></use>
</svg>

    </label>
    
    <div class="search_results results"></div>
  </div>

        <div class="author_header">
          <img src="https://kingdix10.gitee.io/logos/icon_yellow_transparent.png" alt="kingdix10 photo">
          <h2>kingdix10</h2>
        </div>
      <div class="author_bio">
        拾月国度
      </div>
      <a href='https://kingdix10.gitee.io/about/' class="button mt-1" role="button" title='阅读更多'>阅读更多</a>

    
      
    
    <h2 class="mt-4">最新文章</h2>
    <ul class="flex-column">
      <li>
        <a href="https://kingdix10.gitee.io/post/kernel/linux-6.6/kdump_crash/arm64_setup/" class="nav-link" title="ARM64 Crash调试环境搭建">ARM64 Crash调试环境搭建</a>
      </li>
      <li>
        <a href="https://kingdix10.gitee.io/post/kernel/linux-6.6/kdump_crash/help/" class="nav-link" title="Crash帮助信息">Crash帮助信息</a>
      </li>
      <li>
        <a href="https://kingdix10.gitee.io/post/kernel/linux-6.1/thermal/thermal/" class="nav-link" title="linux thermal子系统简介">linux thermal子系统简介</a>
      </li>
      <li>
        <a href="https://kingdix10.gitee.io/post/kernel/linux-6.1/time/clocksource_clockevent/" class="nav-link" title="linux内核时间子系统（三）">linux内核时间子系统（三）</a>
      </li>
      <li>
        <a href="https://kingdix10.gitee.io/post/kernel/linux-6.1/time/timekeeping/" class="nav-link" title="linux内核时间子系统（二）">linux内核时间子系统（二）</a>
      </li>
      <li>
        <a href="https://kingdix10.gitee.io/post/kernel/linux-6.1/time/tim/" class="nav-link" title="linux内核时间子系统（一）">linux内核时间子系统（一）</a>
      </li>
      <li>
        <a href="https://kingdix10.gitee.io/post/kernel/linux-6.1/device_driver/device_model/" class="nav-link" title="Linux内核驱动模型（四）核心结构体">Linux内核驱动模型（四）核心结构体</a>
      </li>
      <li>
        <a href="https://kingdix10.gitee.io/post/kernel/linux-6.1/device_driver/initcall/" class="nav-link" title="Linux内核驱动模型（三）驱动初始化">Linux内核驱动模型（三）驱动初始化</a>
      </li>
      <li>
        <a href="https://kingdix10.gitee.io/post/kernel/linux-6.1/fdt/dt_to_dt/" class="nav-link" title="Linux内核驱动模型（二）设备树转换">Linux内核驱动模型（二）设备树转换</a>
      </li>
      <li>
        <a href="https://kingdix10.gitee.io/post/kernel/linux-6.1/fdt/fdt_dt/" class="nav-link" title="Linux内核驱动模型（一）设备树展开">Linux内核驱动模型（一）设备树展开</a>
      </li>
    </ul>
    <div>
      <h2 class="mt-4 taxonomy" id="categories-section">分类</h2>
      <nav class="tags_nav">
        <a href='https://kingdix10.gitee.io/categories/%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86/' class="post_tag button button_translucent" title="进程管理">
          进程管理
          <span class="button_tally">11</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/categories/%E8%AE%BE%E5%A4%87%E6%A8%A1%E5%9E%8B/' class="post_tag button button_translucent" title="设备模型">
          设备模型
          <span class="button_tally">5</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/categories/4412/' class="post_tag button button_translucent" title="4412">
          4412
          <span class="button_tally">3</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/categories/c%E8%AF%AD%E8%A8%80/' class="post_tag button button_translucent" title="c语言">
          C语言
          <span class="button_tally">3</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/categories/%E5%90%AF%E5%8A%A8%E6%B5%81%E7%A8%8B/' class="post_tag button button_translucent" title="启动流程">
          启动流程
          <span class="button_tally">3</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/categories/%E6%97%B6%E9%97%B4%E5%AD%90%E7%B3%BB%E7%BB%9F/' class="post_tag button button_translucent" title="时间子系统">
          时间子系统
          <span class="button_tally">3</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/categories/kdump-crash/' class="post_tag button button_translucent" title="kdump-crash">
          KDUMP-CRASH
          <span class="button_tally">2</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/categories/%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/' class="post_tag button button_translucent" title="环境搭建">
          环境搭建
          <span class="button_tally">2</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/categories/linux%E5%91%BD%E4%BB%A4/' class="post_tag button button_translucent" title="linux命令">
          LINUX命令
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/categories/thermal%E5%AD%90%E7%B3%BB%E7%BB%9F/' class="post_tag button button_translucent" title="thermal子系统">
          THERMAL子系统
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/categories/%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/' class="post_tag button button_translucent" title="内存管理">
          内存管理
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/categories/%E5%86%85%E6%A0%B8%E5%9F%BA%E7%A1%80/' class="post_tag button button_translucent" title="内核基础">
          内核基础
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/categories/%E5%86%85%E6%A0%B8%E8%B0%83%E8%AF%95/' class="post_tag button button_translucent" title="内核调试">
          内核调试
          <span class="button_tally">1</span>
        </a>
        
        
      </nav>
    </div>
    <div>
      <h2 class="mt-4 taxonomy" id="series-section">专栏</h2>
      <nav class="tags_nav">
        <a href='https://kingdix10.gitee.io/series/%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86/' class="post_tag button button_translucent" title="进程管理">
          进程管理
          <span class="button_tally">11</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/series/%E8%AE%BE%E5%A4%87%E9%A9%B1%E5%8A%A8%E6%A8%A1%E5%9E%8B/' class="post_tag button button_translucent" title="设备驱动模型">
          设备驱动模型
          <span class="button_tally">5</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/series/%E6%97%B6%E9%97%B4%E5%AD%90%E7%B3%BB%E7%BB%9F/' class="post_tag button button_translucent" title="时间子系统">
          时间子系统
          <span class="button_tally">3</span>
        </a>
        
        
      </nav>
    </div>
    <div>
      <h2 class="mt-4 taxonomy" id="tags-section">标签</h2>
      <nav class="tags_nav">
        <a href='https://kingdix10.gitee.io/tags/linux%E5%86%85%E6%A0%B8/' class="post_tag button button_translucent" title="linux内核">
          LINUX内核
          <span class="button_tally">19</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/tags/linux-6.1/' class="post_tag button button_translucent" title="linux-6.1">
          LINUX-6.1
          <span class="button_tally">12</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/tags/linux-6.6/' class="post_tag button button_translucent" title="linux-6.6">
          LINUX-6.6
          <span class="button_tally">9</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/tags/%E5%86%85%E6%A0%B8%E9%A9%B1%E5%8A%A8/' class="post_tag button button_translucent" title="内核驱动">
          内核驱动
          <span class="button_tally">9</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/tags/%E8%BF%9B%E7%A8%8B%E7%AE%A1%E7%90%86/' class="post_tag button button_translucent" title="进程管理">
          进程管理
          <span class="button_tally">6</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/tags/linux/' class="post_tag button button_translucent" title="linux">
          LINUX
          <span class="button_tally">5</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/tags/4412/' class="post_tag button button_translucent" title="4412">
          4412
          <span class="button_tally">3</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/tags/c%E8%AF%AD%E8%A8%80/' class="post_tag button button_translucent" title="c语言">
          C语言
          <span class="button_tally">3</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/tags/%E5%90%AF%E5%8A%A8%E6%B5%81%E7%A8%8B/' class="post_tag button button_translucent" title="启动流程">
          启动流程
          <span class="button_tally">3</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/tags/%E5%B7%A5%E5%85%B7/' class="post_tag button button_translucent" title="工具">
          工具
          <span class="button_tally">3</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/tags/kdump-crash/' class="post_tag button button_translucent" title="kdump-crash">
          KDUMP-CRASH
          <span class="button_tally">2</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/tags/%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/' class="post_tag button button_translucent" title="环境搭建">
          环境搭建
          <span class="button_tally">2</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/tags/arm64/' class="post_tag button button_translucent" title="arm64">
          ARM64
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/tags/u-boot/' class="post_tag button button_translucent" title="u-boot">
          U-BOOT
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/tags/%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/' class="post_tag button button_translucent" title="内存管理">
          内存管理
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/tags/%E5%86%85%E6%A0%B8%E8%B0%83%E8%AF%95/' class="post_tag button button_translucent" title="内核调试">
          内核调试
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/' class="post_tag button button_translucent" title="数据结构">
          数据结构
          <span class="button_tally">1</span>
        </a>
        
        <a href='https://kingdix10.gitee.io/tags/%E8%B0%83%E8%AF%95/' class="post_tag button button_translucent" title="调试">
          调试
          <span class="button_tally">1</span>
        </a>
        
        
      </nav>
    </div>
  </section>
</aside>

  
</div>
    </main><svg width="0" height="0" class="hidden">
  <symbol viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" id="facebook">
    <path d="M437 0H75C33.648 0 0 33.648 0 75v362c0 41.352 33.648 75 75 75h151V331h-60v-90h60v-61c0-49.629 40.371-90 90-90h91v90h-91v61h91l-15 90h-76v181h121c41.352 0 75-33.648 75-75V75c0-41.352-33.648-75-75-75zm0 0"></path>
  </symbol>
  <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18.001 18.001" id="twitter">
    <path d="M15.891 4.013c.808-.496 1.343-1.173 1.605-2.034a8.68 8.68 0 0 1-2.351.861c-.703-.756-1.593-1.14-2.66-1.14-1.043 0-1.924.366-2.643 1.078a3.56 3.56 0 0 0-1.076 2.605c0 .309.039.585.117.819-3.076-.105-5.622-1.381-7.628-3.837-.34.601-.51 1.213-.51 1.846 0 1.301.549 2.332 1.645 3.089-.625-.053-1.176-.211-1.645-.47 0 .929.273 1.705.82 2.388a3.623 3.623 0 0 0 2.115 1.291c-.312.08-.641.118-.979.118-.312 0-.533-.026-.664-.083.23.757.664 1.371 1.291 1.841a3.652 3.652 0 0 0 2.152.743C4.148 14.173 2.625 14.69.902 14.69c-.422 0-.721-.006-.902-.038 1.697 1.102 3.586 1.649 5.676 1.649 2.139 0 4.029-.542 5.674-1.626 1.645-1.078 2.859-2.408 3.639-3.974a10.77 10.77 0 0 0 1.172-4.892v-.468a7.788 7.788 0 0 0 1.84-1.921 8.142 8.142 0 0 1-2.11.593z"
      ></path>
  </symbol>
  <symbol aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" id="mail">
    <path  d="M502.3 190.8c3.9-3.1 9.7-.2 9.7 4.7V400c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V195.6c0-5 5.7-7.8 9.7-4.7 22.4 17.4 52.1 39.5 154.1 113.6 21.1 15.4 56.7 47.8 92.2 47.6 35.7.3 72-32.8 92.3-47.6 102-74.1 131.6-96.3 154-113.7zM256 320c23.2.4 56.6-29.2 73.4-41.4 132.7-96.3 142.8-104.7 173.4-128.7 5.8-4.5 9.2-11.5 9.2-18.9v-19c0-26.5-21.5-48-48-48H48C21.5 64 0 85.5 0 112v19c0 7.4 3.4 14.3 9.2 18.9 30.6 23.9 40.7 32.4 173.4 128.7 16.8 12.2 50.2 41.8 73.4 41.4z"></path>
  </symbol>
  <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" id="calendar">
    <path d="M452 40h-24V0h-40v40H124V0H84v40H60C26.916 40 0 66.916 0 100v352c0 33.084 26.916 60 60 60h392c33.084 0 60-26.916 60-60V100c0-33.084-26.916-60-60-60zm20 412c0 11.028-8.972 20-20 20H60c-11.028 0-20-8.972-20-20V188h432v264zm0-304H40v-48c0-11.028 8.972-20 20-20h24v40h40V80h264v40h40V80h24c11.028 0 20 8.972 20 20v48z"></path>
    <path d="M76 230h40v40H76zm80 0h40v40h-40zm80 0h40v40h-40zm80 0h40v40h-40zm80 0h40v40h-40zM76 310h40v40H76zm80 0h40v40h-40zm80 0h40v40h-40zm80 0h40v40h-40zM76 390h40v40H76zm80 0h40v40h-40zm80 0h40v40h-40zm80 0h40v40h-40zm80-80h40v40h-40z"></path>
  </symbol>
  <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" id="github">
    <path d="M255.968 5.329C114.624 5.329 0 120.401 0 262.353c0 113.536 73.344 209.856 175.104 243.872 12.8 2.368 17.472-5.568 17.472-12.384 0-6.112-.224-22.272-.352-43.712-71.2 15.52-86.24-34.464-86.24-34.464-11.616-29.696-28.416-37.6-28.416-37.6-23.264-15.936 1.728-15.616 1.728-15.616 25.696 1.824 39.2 26.496 39.2 26.496 22.848 39.264 59.936 27.936 74.528 21.344 2.304-16.608 8.928-27.936 16.256-34.368-56.832-6.496-116.608-28.544-116.608-127.008 0-28.064 9.984-51.008 26.368-68.992-2.656-6.496-11.424-32.64 2.496-68 0 0 21.504-6.912 70.4 26.336 20.416-5.696 42.304-8.544 64.096-8.64 21.728.128 43.648 2.944 64.096 8.672 48.864-33.248 70.336-26.336 70.336-26.336 13.952 35.392 5.184 61.504 2.56 68 16.416 17.984 26.304 40.928 26.304 68.992 0 98.72-59.84 120.448-116.864 126.816 9.184 7.936 17.376 23.616 17.376 47.584 0 34.368-.32 62.08-.32 70.496 0 6.88 4.608 14.88 17.6 12.352C438.72 472.145 512 375.857 512 262.353 512 120.401 397.376 5.329 255.968 5.329z"></path>
  </symbol>

  <symbol width="128px" height="128px" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" id="gitee">
      <g id="LOGO" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
          <g id="Artboard-7" transform="translate(-192.000000, -115.000000)" fill="#C71D23">
              <path d="M228,115 C247.882251,115 264,131.117749 264,151 C264,170.882251 247.882251,187 228,187 C208.117749,187 192,170.882251 192,151 C192,131.117749 208.117749,115 228,115 Z M246.223335,131 C246.222967,131 246.2226,131 246.222232,131.001102 L221.33326,131.001102 C213.969504,131.001102 208,136.970606 208,144.334362 L208,169.222232 C208,170.204066 208.795934,171 209.777768,171 L236.000329,171 C242.627564,171 248,165.627564 248,159.000329 L248,148.778425 C248,147.796591 247.204066,147.000657 246.222232,147.000657 L225.7779,147.000657 C224.796248,147.001123 224.000389,147.796773 223.999667,148.778425 L223.998503,153.222667 C223.997802,154.155409 224.715909,154.920565 225.629522,154.994969 L225.775805,155.00042 L225.775805,155.00042 L238.222276,155.000317 C239.155019,155.000295 239.919992,155.718618 239.994164,156.63225 L240.000044,156.77807 L240.000044,156.77807 L240.000044,157.666909 C240.000044,160.612411 237.612243,163.000213 234.66674,163.000213 L217.776621,163.000213 C216.794928,163.000164 215.999101,162.204358 215.999025,161.222665 L215.998559,144.334184 C215.998337,141.462319 218.268172,139.120556 221.111731,139.005187 L221.331716,139.00088 L221.331716,139.00088 L246.21727,139.00088 C247.198674,138.999777 247.994429,138.204515 247.996141,137.223112 L247.998897,132.77887 C248.000609,131.797037 247.205169,131.000609 246.223335,131 Z" id="logo_gitee_g_red"></path>
          </g>
      </g>
  </symbol>

  <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 212 212" id="gitlab">
    <path d="M12.3 74.7h54L43.3 3c-1-3.6-6.4-3.6-7.6 0L12.3 74.8z" />
    <path d="M12.3 74.7L.5 111c-1 3.2 0 6.8 3 8.8l101.6 74-92.5-119z"/>
    <path d="M105 193.7l-38.6-119h-54l92.7 119z"/>
    <path d="M105 193.7l38.7-119H66.4l38.7 119z"/>
    <path d="M105 193.7l38.7-119H198l-93 119z"/>
    <path d="M198 74.7l11.6 36.2c1 3 0 6.6-3 8.6l-101.5 74 93-119z"/>
    <path d="M198 74.7h-54.3L167 3c1.2-3.6 6.4-3.6 7.6 0L198 74.8z"/>
  </symbol>
  <symbol viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" id="rss">
    <circle cx="3.429" cy="20.571" r="3.429"></circle>
    <path d="M11.429 24h4.57C15.999 15.179 8.821 8.001 0 8v4.572c6.302.001 11.429 5.126 11.429 11.428z"></path>
    <path d="M24 24C24 10.766 13.234 0 0 0v4.571c10.714 0 19.43 8.714 19.43 19.429z"></path>
  </symbol>
  <symbol viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" id="linkedin">
    <path d="M437 0H75C33.648 0 0 33.648 0 75v362c0 41.352 33.648 75 75 75h362c41.352 0 75-33.648 75-75V75c0-41.352-33.648-75-75-75zM181 406h-60V196h60zm0-240h-60v-60h60zm210 240h-60V286c0-16.54-13.46-30-30-30s-30 13.46-30 30v120h-60V196h60v11.309C286.719 202.422 296.93 196 316 196c40.691.043 75 36.547 75 79.688zm0 0"></path>
  </symbol>
  <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 612 612" id="to-top">
    <path d="M604.501 440.509L325.398 134.956c-5.331-5.357-12.423-7.627-19.386-7.27-6.989-.357-14.056 1.913-19.387 7.27L7.499 440.509c-9.999 10.024-9.999 26.298 0 36.323s26.223 10.024 36.222 0l262.293-287.164L568.28 476.832c9.999 10.024 26.222 10.024 36.221 0 9.999-10.023 9.999-26.298 0-36.323z"></path>
  </symbol>
  <symbol viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" id="carly">
    <path d="M504.971 239.029L448 182.059V84c0-46.317-37.682-84-84-84h-44c-13.255 0-24 10.745-24 24s10.745 24 24 24h44c19.851 0 36 16.149 36 36v108c0 6.365 2.529 12.47 7.029 16.971L454.059 256l-47.029 47.029A24.002 24.002 0 0 0 400 320v108c0 19.851-16.149 36-36 36h-44c-13.255 0-24 10.745-24 24s10.745 24 24 24h44c46.318 0 84-37.683 84-84v-98.059l56.971-56.971c9.372-9.372 9.372-24.568 0-33.941zM112 192V84c0-19.851 16.149-36 36-36h44c13.255 0 24-10.745 24-24S205.255 0 192 0h-44c-46.318 0-84 37.683-84 84v98.059l-56.971 56.97c-9.373 9.373-9.373 24.568 0 33.941L64 329.941V428c0 46.317 37.682 84 84 84h44c13.255 0 24-10.745 24-24s-10.745-24-24-24h-44c-19.851 0-36-16.149-36-36V320c0-6.365-2.529-12.47-7.029-16.971L57.941 256l47.029-47.029A24.002 24.002 0 0 0 112 192z"></path>
  </symbol>
  <symbol viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" id="copy">
    <path d="M23 2.75A2.75 2.75 0 0 0 20.25 0H8.75A2.75 2.75 0 0 0 6 2.75v13.5A2.75 2.75 0 0 0 8.75 19h11.5A2.75 2.75 0 0 0 23 16.25zM18.25 14.5h-7.5a.75.75 0 0 1 0-1.5h7.5a.75.75 0 0 1 0 1.5zm0-3h-7.5a.75.75 0 0 1 0-1.5h7.5a.75.75 0 0 1 0 1.5zm0-3h-7.5a.75.75 0 0 1 0-1.5h7.5a.75.75 0 0 1 0 1.5z"></path>
    <path d="M8.75 20.5a4.255 4.255 0 0 1-4.25-4.25V2.75c0-.086.02-.166.025-.25H3.75A2.752 2.752 0 0 0 1 5.25v16A2.752 2.752 0 0 0 3.75 24h12a2.752 2.752 0 0 0 2.75-2.75v-.75z"></path>
  </symbol>
  <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512.001 512.001" id="closeme">
    <path d="M284.286 256.002L506.143 34.144c7.811-7.811 7.811-20.475 0-28.285-7.811-7.81-20.475-7.811-28.285 0L256 227.717 34.143 5.859c-7.811-7.811-20.475-7.811-28.285 0-7.81 7.811-7.811 20.475 0 28.285l221.857 221.857L5.858 477.859c-7.811 7.811-7.811 20.475 0 28.285a19.938 19.938 0 0 0 14.143 5.857 19.94 19.94 0 0 0 14.143-5.857L256 284.287l221.857 221.857c3.905 3.905 9.024 5.857 14.143 5.857s10.237-1.952 14.143-5.857c7.811-7.811 7.811-20.475 0-28.285L284.286 256.002z"></path>
  </symbol>
  <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" id="open-menu">
    <path d="M492 236H20c-11.046 0-20 8.954-20 20s8.954 20 20 20h472c11.046 0 20-8.954 20-20s-8.954-20-20-20zm0-160H20C8.954 76 0 84.954 0 96s8.954 20 20 20h472c11.046 0 20-8.954 20-20s-8.954-20-20-20zm0 320H20c-11.046 0-20 8.954-20 20s8.954 20 20 20h472c11.046 0 20-8.954 20-20s-8.954-20-20-20z"></path>
  </symbol>
  <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" id="instagram">
    <path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z"/>
  </symbol>
  <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" id=youtube>
    <path d="M19.615 3.184c-3.604-.246-11.631-.245-15.23 0-3.897.266-4.356 2.62-4.385 8.816.029 6.185.484 8.549 4.385 8.816 3.6.245 11.626.246 15.23 0 3.897-.266 4.356-2.62 4.385-8.816-.029-6.185-.484-8.549-4.385-8.816zm-10.615 12.816v-8l8 3.993-8 4.007z"/>
  </symbol>
  <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" id="stackoverflow">
    <path d="M21 27v-8h3v11H0V19h3v8h18z"></path><path d="M17.1.2L15 1.8l7.9 10.6 2.1-1.6L17.1.2zm3.7 14.7L10.6 6.4l1.7-2 10.2 8.5-1.7 2zM7.2 12.3l12 5.6 1.1-2.4-12-5.6-1.1 2.4zm-1.8 6.8l13.56 1.96.17-2.38-13.26-2.55-.47 2.97zM19 25H5v-3h14v3z"></path>
  </symbol>
  <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" id="xing">
    <path d="M18.188 0c-.517 0-.741.325-.927.66 0 0-7.455 13.224-7.702 13.657.015.024 4.919 9.023 4.919 9.023.17.308.436.66.967.66h3.454c.211 0 .375-.078.463-.22.089-.151.089-.346-.009-.536l-4.879-8.916c-.004-.006-.004-.016 0-.022L22.139.756c.095-.191.097-.387.006-.535C22.056.078 21.894 0 21.686 0h-3.498zM3.648 4.74c-.211 0-.385.074-.473.216-.09.149-.078.339.02.531l2.34 4.05c.004.01.004.016 0 .021L1.86 16.051c-.099.188-.093.381 0 .529.085.142.239.234.45.234h3.461c.518 0 .766-.348.945-.667l3.734-6.609-2.378-4.155c-.172-.315-.434-.659-.962-.659H3.648v.016z"/>
  </symbol>
  <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 71 55" id="discord">
    <path d="M60.1045 4.8978C55.5792 2.8214 50.7265 1.2916 45.6527 0.41542C45.5603 0.39851 45.468 0.440769 45.4204 0.525289C44.7963 1.6353 44.105 3.0834 43.6209 4.2216C38.1637 3.4046 32.7345 3.4046 27.3892 4.2216C26.905 3.0581 26.1886 1.6353 25.5617 0.525289C25.5141 0.443589 25.4218 0.40133 25.3294 0.41542C20.2584 1.2888 15.4057 2.8186 10.8776 4.8978C10.8384 4.9147 10.8048 4.9429 10.7825 4.9795C1.57795 18.7309 -0.943561 32.1443 0.293408 45.3914C0.299005 45.4562 0.335386 45.5182 0.385761 45.5576C6.45866 50.0174 12.3413 52.7249 18.1147 54.5195C18.2071 54.5477 18.305 54.5139 18.3638 54.4378C19.7295 52.5728 20.9469 50.6063 21.9907 48.5383C22.0523 48.4172 21.9935 48.2735 21.8676 48.2256C19.9366 47.4931 18.0979 46.6 16.3292 45.5858C16.1893 45.5041 16.1781 45.304 16.3068 45.2082C16.679 44.9293 17.0513 44.6391 17.4067 44.3461C17.471 44.2926 17.5606 44.2813 17.6362 44.3151C29.2558 49.6202 41.8354 49.6202 53.3179 44.3151C53.3935 44.2785 53.4831 44.2898 53.5502 44.3433C53.9057 44.6363 54.2779 44.9293 54.6529 45.2082C54.7816 45.304 54.7732 45.5041 54.6333 45.5858C52.8646 46.6197 51.0259 47.4931 49.0921 48.2228C48.9662 48.2707 48.9102 48.4172 48.9718 48.5383C50.038 50.6034 51.2554 52.5699 52.5959 54.435C52.6519 54.5139 52.7526 54.5477 52.845 54.5195C58.6464 52.7249 64.529 50.0174 70.6019 45.5576C70.6551 45.5182 70.6887 45.459 70.6943 45.3942C72.1747 30.0791 68.2147 16.7757 60.1968 4.9823C60.1772 4.9429 60.1437 4.9147 60.1045 4.8978ZM23.7259 37.3253C20.2276 37.3253 17.3451 34.1136 17.3451 30.1693C17.3451 26.225 20.1717 23.0133 23.7259 23.0133C27.308 23.0133 30.1626 26.2532 30.1066 30.1693C30.1066 34.1136 27.28 37.3253 23.7259 37.3253ZM47.3178 37.3253C43.8196 37.3253 40.9371 34.1136 40.9371 30.1693C40.9371 26.225 43.7636 23.0133 47.3178 23.0133C50.9 23.0133 53.7545 26.2532 53.6986 30.1693C53.6986 34.1136 50.9 37.3253 47.3178 37.3253Z"/>
  </symbol>
  <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 17 18" id="mastodon">
    <path
    fill="#ffffff"
    d="m 15.054695,9.8859583 c -0.22611,1.1632697 -2.02517,2.4363497 -4.09138,2.6830797 -1.0774504,0.12856 -2.1382704,0.24673 -3.2694704,0.19484 -1.84996,-0.0848 -3.30971,-0.44157 -3.30971,-0.44157 0,0.1801 0.0111,0.35157 0.0333,0.51194 0.24051,1.82571 1.81034,1.93508 3.29737,1.98607 1.50088,0.0514 2.8373104,-0.37004 2.8373104,-0.37004 l 0.0617,1.35686 c 0,0 -1.0498104,0.56374 -2.9199404,0.66742 -1.03124,0.0567 -2.3117,-0.0259 -3.80308,-0.42069 -3.23454998,-0.85613 -3.79081998,-4.304 -3.87592998,-7.8024197 -0.026,-1.03871 -0.01,-2.01815 -0.01,-2.83732 0,-3.57732 2.34385998,-4.62587996 2.34385998,-4.62587996 1.18184,-0.54277 3.20976,-0.77101 5.318,-0.7882499985409 h 0.0518 C 9.8267646,0.01719834 11.856025,0.24547834 13.037775,0.78824834 c 0,0 2.34377,1.04855996 2.34377,4.62587996 0,0 0.0294,2.63937 -0.32687,4.47183"/>
 <path
    fill="#000000"
    d="m 12.616925,5.6916583 v 4.3315297 h -1.71607 V 5.8189683 c 0,-0.88624 -0.37289,-1.33607 -1.1187604,-1.33607 -0.82467,0 -1.23799,0.53361 -1.23799,1.58875 v 2.30122 h -1.70594 v -2.30122 c 0,-1.05514 -0.4134,-1.58875 -1.23808,-1.58875 -0.74587,0 -1.11876,0.44983 -1.11876,1.33607 v 4.2042197 h -1.71607 V 5.6916583 c 0,-0.88527 0.22541,-1.58876 0.67817,-2.10922 0.46689,-0.52047 1.07833,-0.78727 1.83735,-0.78727 0.87816,0 1.54317,0.33752 1.98288,1.01267 l 0.42744,0.71655 0.42753,-0.71655 c 0.43961,-0.67515 1.10463,-1.01267 1.9828704,-1.01267 0.75893,0 1.37037,0.2668 1.83735,0.78727 0.45268,0.52046 0.67808,1.22395 0.67808,2.10922"/>
  </symbol>
</svg>

<footer class="footer">
  <div class="footer_inner wrap pale">
    <img src='https://kingdix10.gitee.io/icons/copy.svg' class="icon icon_2 transparent" alt="拾月国度">
    <p>Copyright&nbsp;2018-&nbsp;<span class="year"></span>&nbsp;拾月国度. All Rights Reserved</p><a class="to_top" href="#documentTop">
  <svg class="icon">
  <title>to-top</title>
  <use xlink:href="#to-top"></use>
</svg>

</a>

  </div>
</footer>

<script type="text/javascript" src="https://kingdix10.gitee.io/zh-cn/js/bundle.352f6b8ac853443fc909370d968a769ffa303b36042cc66849f2d48d9e5dd951ee86c06130908f5d77ea0e55ec8fed0e5dc26f0f14bbd4ad6dcf35999232e5bc.js" integrity="sha512-NS9rishTRD/JCTcNlop2n/owOzYELMZoSfLUjZ5d2VHuhsBhMJCPXXfqDlXsj&#43;0OXcJvDxS71K1tzzWZkjLlvA==" crossorigin="anonymous"></script>

  <script src="https://kingdix10.gitee.io/js/search.min.b19f217359693afb8f0abd75ca8de6becceec41f5304950fc48e165914ef227f44d10005d02a281a66e33b482e2ff27e6eb893111505deb4f072c307e1f887bb.js"></script>

  </body>
</html>
